%{
	#include <stdio.h>
	#include "ast.h"
	
 	int yylex();
	void yyerror(char* msg);
	int error_line;
%}
%union {
	int int_type;
	float float_type;
	char* str_type;
	TreeNode* node_type;
}
%token <node_type> INT FLOAT
%token <node_type> BLANK TAB SEMI ID COMMA RELOP AND OR LC RC STRUCT RETURN IF WHILE TYPE INT_TYPE FLOAT_TYPE LT LE EQ NE GT GE ELSE LB RB LP RP NOT DOT MINUS PLUS STAR DIV ASSIGNOP

%type <node_type> Program ExtDefList ExtDef ExtDecList Specifier StructSpecifier OptTag Tag VarDec FunDec VarList ParamDec CompSt StmtList Stmt DefList Def DecList Dec Exp Args

%nonassoc LOWER_THAN_ELSE
%nonassoc ELSE

%right ASSIGNOP
%left OR
%left AND
%left RELOP
%left MINUS
%left PLUS
%left DIV
%left STAR
%right NOT
%right NEG
%left DOT
%left LB RB
%left LP RP

%%
//A1.2
Program :
	ExtDefList {TreeNode* temp[MAX_CHILDREN] = {$1}; $$=new_node(new_node_syntax("Program", @$.first_line), temp, 1); root=$$;}
	;
ExtDefList : {$$=new_node_null();}
	| ExtDef ExtDefList {TreeNode* temp[MAX_CHILDREN] = {$1,$2}; $$=new_node(new_node_syntax("ExtDefList", @$.first_line), temp, 2);}
	;
ExtDef  : Specifier ExtDecList SEMI {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("ExtDef", @$.first_line), temp, 3);}
	|  Specifier SEMI {TreeNode* temp[MAX_CHILDREN] = {$1,$2}; $$=new_node(new_node_syntax("ExtDef", @$.first_line), temp, 2);}
	|  Specifier FunDec CompSt {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("ExtDef", @$.first_line), temp, 3);}
	;
ExtDecList :VarDec {TreeNode* temp[MAX_CHILDREN] = {$1}; $$=new_node(new_node_syntax("ExtDecList", @$.first_line), temp, 1);}
	| VarDec COMMA ExtDecList {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("ExtDecList", @$.first_line), temp, 3);}
	;
//A.1.3
Specifier : TYPE {TreeNode* temp[MAX_CHILDREN] = {$1}; $$=new_node(new_node_syntax("Specifier", @$.first_line), temp, 1);}
	| StructSpecifier {TreeNode* temp[MAX_CHILDREN] = {$1}; $$=new_node(new_node_syntax("Specifier", @$.first_line), temp, 1);}
	;
StructSpecifier : STRUCT OptTag LC DefList RC {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3,$4,$5}; $$=new_node(new_node_syntax("StructSpecifier", @$.first_line), temp, 5);}
	| STRUCT Tag {TreeNode* temp[MAX_CHILDREN] = {$1,$2}; $$=new_node(new_node_syntax("StructSpecifier", @$.first_line), temp, 2);}
	;
OptTag : {$$=new_node_null();}
	|ID {TreeNode* temp[MAX_CHILDREN] = {$1}; $$=new_node(new_node_syntax("OptTag", @$.first_line), temp, 1);}
	;
Tag  : ID {TreeNode* temp[MAX_CHILDREN] = {$1}; $$=new_node(new_node_syntax("Tag", @$.first_line), temp, 1);}
	;
//A.1.4
VarDec : ID {TreeNode* temp[MAX_CHILDREN] = {$1}; $$=new_node(new_node_syntax("VarDec", @$.first_line), temp, 1);}
	| VarDec LB INT RB {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3,$4}; $$=new_node(new_node_syntax("VarDec", @$.first_line), temp, 4);}
	;
FunDec : ID LP VarList RP {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3,$4}; $$=new_node(new_node_syntax("FunDec", @$.first_line), temp, 4);}
	| ID LP RP {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("FunDec", @$.first_line), temp, 3);}
	;
VarList: ParamDec COMMA VarList {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("VarList", @$.first_line), temp, 3);}
	| ParamDec {TreeNode* temp[MAX_CHILDREN] = {$1}; $$=new_node(new_node_syntax("VarList", @$.first_line), temp, 1);}
	;
ParamDec : Specifier VarDec {TreeNode* temp[MAX_CHILDREN] = {$1,$2}; $$=new_node(new_node_syntax("ParamDec", @$.first_line), temp, 2);}
	;
//A.1.5
CompSt:  LC DefList StmtList RC {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3,$4}; $$=new_node(new_node_syntax("CompSt", @$.first_line), temp, 4);}
	;
StmtList: {$$=new_node_null();}
	|Stmt StmtList {TreeNode* temp[MAX_CHILDREN] = {$1,$2}; $$=new_node(new_node_syntax("StmtList", @$.first_line), temp, 2);}
	;
Stmt : Exp SEMI {TreeNode* temp[MAX_CHILDREN] = {$1,$2}; $$=new_node(new_node_syntax("Stmt", @$.first_line), temp, 2);}
	| CompSt {TreeNode* temp[MAX_CHILDREN] = {$1}; $$=new_node(new_node_syntax("Stmt", @$.first_line), temp, 1);}
	| RETURN Exp SEMI {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("Stmt", @$.first_line), temp, 3);}
	| IF LP Exp RP Stmt %prec LOWER_THAN_ELSE {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3,$4,$5}; $$=new_node(new_node_syntax("Stmt", @$.first_line), temp, 5);}
	| IF LP Exp RP Stmt ELSE Stmt {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3,$4,$5,$6,$7}; $$=new_node(new_node_syntax("Stmt", @$.first_line), temp, 7);}
	| WHILE LP Exp RP Stmt {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3,$4,$5}; $$=new_node(new_node_syntax("Stmt", @$.first_line), temp, 5);}
	;

//A.1.6
DefList: {$$=new_node_null();}
	| Def DefList {TreeNode* temp[MAX_CHILDREN] = {$1,$2}; $$=new_node(new_node_syntax("DefList", @$.first_line), temp, 2);}
	;
Def : Specifier DecList SEMI {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("Def", @$.first_line), temp, 3);}
	;
DecList : Dec {TreeNode* temp[MAX_CHILDREN] = {$1}; $$=new_node(new_node_syntax("DecList", @$.first_line), temp, 1);}
	| Dec COMMA DecList {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("DecList", @$.first_line), temp, 3);}
	;
Dec : VarDec {TreeNode* temp[MAX_CHILDREN] = {$1}; $$=new_node(new_node_syntax("Dec", @$.first_line), temp, 1);}
	| VarDec ASSIGNOP Exp {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("Dec", @$.first_line), temp, 3);}
	;
//A.1.7
Exp : Exp ASSIGNOP Exp {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("Exp", @$.first_line), temp, 3);}
	| Exp AND Exp {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("Exp", @$.first_line), temp, 3);}
	| Exp OR Exp {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("Exp", @$.first_line), temp, 3);}
	| Exp RELOP Exp {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("Exp", @$.first_line), temp, 3);}
	| Exp PLUS Exp {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("Exp", @$.first_line), temp, 3);}
	| Exp MINUS Exp {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("Exp", @$.first_line), temp, 3);}
	| Exp STAR Exp {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("Exp", @$.first_line), temp, 3);}
	| Exp DIV Exp {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("Exp", @$.first_line), temp, 3);}
	| LP Exp RP {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("Exp", @$.first_line), temp, 3);}
	| MINUS Exp %prec NEG {TreeNode* temp[MAX_CHILDREN] = {$1,$2}; $$=new_node(new_node_syntax("Exp", @$.first_line), temp, 2);}
	| NOT Exp {TreeNode* temp[MAX_CHILDREN] = {$1,$2}; $$=new_node(new_node_syntax("Exp", @$.first_line), temp, 2);}
	| ID LP Args RP {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3,$4}; $$=new_node(new_node_syntax("Exp", @$.first_line), temp, 4);}
	| ID LP RP {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("Exp", @$.first_line), temp, 3);}
	| Exp LB Exp RB {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3,$4}; $$=new_node(new_node_syntax("Exp", @$.first_line), temp, 4);}
	| Exp DOT ID {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("Exp", @$.first_line), temp, 3);}
	| ID {TreeNode* temp[MAX_CHILDREN] = {$1}; $$=new_node(new_node_syntax("Exp", @$.first_line), temp, 1);}
	| INT {TreeNode* temp[MAX_CHILDREN] = {$1}; $$=new_node(new_node_syntax("Exp", @$.first_line), temp, 1);}
	| FLOAT {TreeNode* temp[MAX_CHILDREN] = {$1}; $$=new_node(new_node_syntax("Exp", @$.first_line), temp, 1);}
	;

Args : Exp COMMA Args {TreeNode* temp[MAX_CHILDREN] = {$1,$2,$3}; $$=new_node(new_node_syntax("Args", @$.first_line), temp, 3);}
	| Exp {TreeNode* temp[MAX_CHILDREN] = {$1}; $$=new_node(new_node_syntax("Args", @$.first_line), temp, 1);}
	;


Stmt : error SEMI {};
CompSt : error RC {};
Def: error SEMI {};


%%
